package projbd;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigInteger;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;


public class OrderSizeNumSchemeXMLParser extends DefaultHandler {
    
    private static BigInteger MAX_VALUE = new BigInteger("1000000000000");
    
    private ArrayList<FileReader> files = new ArrayList<FileReader>();

    private Stack<OrderSizeNumSchemeNode> currentPath = new Stack<OrderSizeNumSchemeNode>();
    
    private int pk = 0;

       
    public OrderSizeNumSchemeXMLParser() {
        super();
    }

    @Override
    public void startDocument() throws SAXException {
        
        System.out.println("start document");
    }

    @Override
    public void endDocument() throws SAXException {
        
        System.out.println("end document");
    }

    @Override
    public void characters(char ch[], int start, int length) {
        
        String text = new String(ch, start, length);
        text = text.trim();
        
        if(text == null || text.isEmpty())
            return;
        
        System.out.println("charac: " + text);
        OrderSizeNumSchemeNode node = new OrderSizeNumSchemeNode();
        node.setValue(text);
        currentPath.push(node);
        
        createNodeInsertSQL();
        
        currentPath.pop();
    }
    
    @Override
    public void startElement(String uri, String name, String qName, Attributes atts) {
        
        System.out.println("startElement: " + name);
        
        OrderSizeNumSchemeNode node = new OrderSizeNumSchemeNode();
        node.setValue(name);
        node.setAttributes(atts.toString());
        currentPath.push(node);
        
        createNodeInsertSQL();
    }
    
     public void createNodeInsertSQL() {
        
        /*
        id    		integer PRIMARY KEY,
	parent_id    	integer references order_size_edges(id),
	oder    	integer,
	size    	integer,
	path_id    	integer references paths(id),
	value    	text,
        attributes      text
        */
         
        StringBuilder sql = new StringBuilder();
        sql.append("INSERT INTO order_size_edges (id, parent_id, order, size, value) VALUES (");
        
        // ID
        int id = pk++;
        sql.append(id + ", ");
        
        OrderSizeNumSchemeNode node = currentPath.lastElement();
        int pathSize = currentPath.size();
        if(pathSize == 1) {
            sql.append(id + ", ");
            sql.append(0 + ", ");
            sql.append(MAX_VALUE + ", ");
            sql.append(node.getValue() + ")");
            
            node.setPk(id);
            node.setOrder(BigInteger.ONE);
            node.setSize(MAX_VALUE);

            System.out.println(sql);
            return;
        }
        
        OrderSizeNumSchemeNode father = currentPath.elementAt(currentPath.size()-2);
        
        // PARENT_ID
        int parent_id = father.getPk();
        sql.append(parent_id + ", ");
        
        // ORDER
        BigInteger order;
        if(father.getCurrentSonOrder() != null) {
            order = father.getCurrentSonOrder().add(father.getCurrentSonSize()).add(BigInteger.ONE);
        } else {
            order = father.getSize().divide(BigInteger.TEN).add(father.getOrder());
            father.setFirstSonOrder(order);
        }
               
        // SIZE
        BigInteger size;
        if(father.getCurrentSonSize() != null) {

            BigInteger fatherSizeUsed = father.getCurrentSonOrder().subtract(father.getFirstSonOrder());
            fatherSizeUsed = fatherSizeUsed.add(father.getCurrentSonSize());
            BigInteger fatherSizeAvailable = father.getSize().divide(new BigInteger("2")).subtract(fatherSizeUsed);
            size = fatherSizeAvailable.divide(new BigInteger("8"));

        } else {
            size = father.getSize().divide(new BigInteger("8"));
        }

        father.setCurrentSonOrder(order);
        father.setCurrentSonSize(size);
        
        sql.append(order + ", ");
        sql.append(size + ", ");
        sql.append(node.getValue() + ")");
        
        node.setPk(pk);
        node.setOrder(order);
        node.setSize(size);
        
        System.out.println(sql);
    }
    
    @Override
    public void endElement(String uri, String name, String qName) {
        
        System.out.println("endElement: " + name);
        
        OrderSizeNumSchemeNode node = this.currentPath.pop();
        
        if(! node.getValue().equals(name))
            System.out.println("OrderSizeNumScheme: error at endElement !");
    }
        
    public void addFile(String path) {
        
        FileReader file = null;
        
        if(path == null)
            return;
        
        try {
            
            file = new FileReader(path);
            
        } catch (FileNotFoundException ex) {
            System.out.println("Error creating FileReader of XML file !");
            Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
            return;
        }
        
        files.add(file);
    }
    
    public void run() {

        XMLReader xr;
        
        try {
            xr = XMLReaderFactory.createXMLReader();        
        } catch (SAXException ex) {
            Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
            return;
        }
        
        xr.setContentHandler(this);
	xr.setErrorHandler(this);

        for(FileReader file: files) {
            
            try {
                
                xr.parse(new InputSource(file));
                
            } catch (IOException ex) {
                Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SAXException ex) {
                Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
            }
	}
        
    }
    
    public static void main(String[] args) throws SQLException {
        
        OrderSizeNumSchemeXMLParser parser = new OrderSizeNumSchemeXMLParser();
        
        parser.addFile("input/teste.xml");
        
        parser.run();
        
    }
    
}
